from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import pandas as pd
import numpy as np
from bayes_opt import BayesianOptimization

# 读取数据
data = pd.read_csv("E:/GraduateDesign/LinearUse.csv")
X = data.drop(columns=['rrr'])
y = data['rrr']

# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, shuffle=True)


# 定义贝叶斯优化目标函数
def lr_cv(fit_intercept, positive):
    # 将连续参数转换为布尔值
    fit_intercept = bool(round(fit_intercept))
    positive = bool(round(positive))

    model = LinearRegression(fit_intercept=fit_intercept, positive=positive)

    # 使用5折交叉验证计算RMSE
    neg_mse = cross_val_score(model, X_train, y_train,
                              scoring='neg_mean_squared_error',
                              cv=5)
    rmse = np.mean(np.sqrt(-neg_mse))  # 计算平均RMSE
    return -rmse  # 贝叶斯优化默认最大化目标值，返回负RMSE实现最小化


# 设置参数搜索空间
pbounds = {
    'fit_intercept': (0, 1),  # 贝叶斯优化处理为连续值，实际会被转换为0/1
    'positive': (0, 1)
}

# 初始化优化器
optimizer = BayesianOptimization(
    f=lr_cv,
    pbounds=pbounds,
    random_state=42
)

# 运行优化（初始点2个，迭代10次）
optimizer.maximize(init_points=2, n_iter=10)

# 获取最佳参数
best_params = optimizer.max['params']
best_model = LinearRegression(
    fit_intercept=bool(round(best_params['fit_intercept'])),
    positive=bool(round(best_params['positive']))
)

# 训练最终模型
best_model.fit(X_train, y_train)

# 测试集评估
y_pred = best_model.predict(X_test)
print(f"优化后RMSE: {mean_squared_error(y_test, y_pred, squared=False)}")
print(f"优化后MAE: {mean_absolute_error(y_test, y_pred)}")

# # （可选）输出最佳参数
# print("\n最佳参数组合：")
# for k, v in best_params.items():
#     print(f"{k}: {bool(round(v))}")


# 新增MAPE指标（处理除零问题）
# 方法1: 自动过滤零值样本
mask = y_test != 0
mape = np.mean(np.abs((y_test[mask] - y_pred[mask]) / y_test[mask])) * 100

# 方法2: 添加微小值防止除零（如果数据允许）
# epsilon = 1e-10
# mape = np.mean(np.abs((y_test - y_pred) / (y_test + epsilon))) * 100

print(f"优化后MAPE: {mape:.2f}%")


# 新增R²指标
r2 = r2_score(y_test, y_pred)
print(f"优化后R²: {r2}")
